package com.polaris.live.ui.live.widget

import android.content.Context
import android.graphics.Typeface
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewTreeObserver
import android.widget.LinearLayout
import androidx.annotation.CallSuper
import androidx.annotation.IdRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.lifecycle.ViewTreeLifecycleOwner
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.blankj.utilcode.util.KeyboardUtils
import com.blankj.utilcode.util.ScreenUtils
import com.blankj.utilcode.util.StringUtils
import com.chad.library.adapter.base.listener.OnItemChildClickListener
import com.polaris.live.R
import com.polaris.live.adapter.live.LiveMessageAdapter
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.constant.AppConst
import com.polaris.live.common.ext.dp
import com.polaris.live.common.ext.setOnSingleClickListener
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.util.DebounceHelper
import com.polaris.live.common.util.ViewUtils
import com.polaris.live.constant.LiveConst
import com.polaris.live.constant.LiveConst.LivePage
import com.polaris.live.constant.UserConst
import com.polaris.live.databinding.WidgetCallMessageBinding
import com.polaris.live.databinding.WidgetGameCallMessageBinding
import com.polaris.live.databinding.WidgetLiveBaseMessageBinding
import com.polaris.live.databinding.WidgetLiveMessageBinding
import com.polaris.live.databinding.WidgetPartyGameMessageBinding
import com.polaris.live.databinding.WidgetPartyMessageBinding
import com.polaris.live.im.sfs.LIVE_INVITE_FOLLOW
import com.polaris.live.im.sfs.LIVE_PUBLIC_SCREEN
import com.polaris.live.im.sfs.bean.live.LiveRoomInfo
import com.polaris.live.im.sfs.bean.live.SendLiveMessage
import com.polaris.live.im.sfs.bean.live.ext.MessageUserExtBean
import com.polaris.live.im.sfs.bean.live.payload.InviteFollowPayloadBean
import com.polaris.live.im.sfs.bean.live.payload.InviteGiftPayloadBean
import com.polaris.live.im.sfs.bean.live.payload.TipsPayloadBean
import com.polaris.live.resp.back_resp.CallVo
import com.polaris.live.resp.go_resp.SendGiftBean
import com.polaris.live.translation.R.string
import com.polaris.live.ui.game.GameUtils
import com.polaris.live.ui.live.widget.AbstractLiveMessageView.Companion.CHAT
import com.polaris.live.ui.live.widget.listener.OnCallClickListener
import com.polaris.live.ui.live.widget.listener.OnReportListener
import com.polaris.live.ui.live.widget.listener.OnSendFollowerListener
import com.polaris.live.ui.live.widget.listener.OnSendGiftListener
import com.polaris.live.ui.live.widget.listener.OnSendUpSeatListener
import com.polaris.live.ui.live.widget.listener.OnUserProfileClickListener
import com.polaris.live.ui.luckybag.fragment.dialog.LuckyBagMessageDialogFragment
import com.polaris.live.ui.party.widget.PartyBottomView
import com.polaris.live.utils.fragment.FragmentUtils
import com.polaris.live.utils.fragment.showNewDialogFragment
import com.polaris.live.utils.route.RouterUtils
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.abs
import kotlin.math.min

/**
 * LiveMessageView
 *
 * @author Created by lucas on 2023/11/7 15:59
 */
open class AbstractLiveMessageView(context: Context, attributeSet: AttributeSet) :
    ConstraintLayout(context, attributeSet) {

    val mBinding = WidgetLiveBaseMessageBinding.inflate(LayoutInflater.from(context), this)

    protected val mAdapter by lazy {
        LiveMessageAdapter {
            findViewTreeLifecycleOwner()?.lifecycleScope
        }
    }

    private val mLayoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)

    var mLivePage: Int? = null

    var mLiveInfo: LiveRoomInfo? = null

    //当前状态
    protected var mPublicType = ALL

    //记录未读数量
    private var mNotReadNum = 0

    //滑动标识
    private var mScrollState = RecyclerView.SCROLL_STATE_IDLE
    private var mManualScrollFlag = false

    private val mCacheDataSet = mutableListOf<SendLiveMessage>()
    private var mLastTime = 0L
    private var mPostMsgJob: Job? = null

    protected var mOnSendGiftListener: OnSendGiftListener? = null
    protected var mOnUserProfileClickListener: OnUserProfileClickListener? = null
    protected var mOnCallClickListener: OnCallClickListener? = null
    protected var mOnSendFollowerListener: OnSendFollowerListener? = null
    protected var mOnSendUpSeatListener: OnSendUpSeatListener? = null
    protected var mOnReportListener: OnReportListener? = null

    init {
        mLayoutManager.stackFromEnd = true
        mBinding.messageRecycler.apply {
            layoutManager = mLayoutManager
            adapter = mAdapter
            itemAnimator = null
        }

        //未读消息点击事件  点击后回到最底部
        mBinding.llNotLook.setOnSingleClickListener {
            smoothScrollToBottom()
            hideNotRead()
        }

        //公屏消息监听如果滑动到最底部就修改未读数量
        mBinding.messageRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                mScrollState = newState

                mManualScrollFlag = newState != RecyclerView.SCROLL_STATE_IDLE
                        || mLayoutManager.findFirstVisibleItemPosition() > 1
                if (newState == RecyclerView.SCROLL_STATE_IDLE && !mManualScrollFlag) {
                    hideNotRead()
                }
            }
        })
        mAdapter.setOnItemClickListener { _, _, position ->
            val item = mAdapter.data[position]
            if (item.ext is MessageUserExtBean) {
                DebounceHelper.singleClick {
                    mOnUserProfileClickListener?.onUserProfile(item.ext.user.userId)
                }
            }
        }
    }

    fun initData(@LivePage page: Int, liveInfo: LiveRoomInfo) {
        mLivePage = page
        mLiveInfo = liveInfo
    }

    fun initPage(@LivePage page: Int) {
        mLivePage = page
    }

    fun itemClick(
        @IdRes viewId: Int,
        position: Int,
        userId: Long?,
        sourceType: Int,
        objectId: Long?,
    ) {
        val item = mAdapter.data[position]
        when (viewId) {
            //邀请关注
            R.id.call_follower_ad_im -> {
                if (userId == null || objectId == null) {
                    return
                }
                val payload = item.payload as InviteFollowPayloadBean

                mOnSendFollowerListener?.onFollowerGift(
                    SendGiftBean(
                        recipient = userId,
                        giftId = payload.gift.id,
                        count = 1,
                        sourceType = sourceType,
                        objectId = objectId,
                        payload = payload.gift.payload
                    )
                )
                mAdapter.removeAt(position)
            }
            //邀请送礼物
            R.id.call_gift_gift -> {
                if (userId == null || objectId == null) {
                    return
                }

                val payload = item.payload as InviteGiftPayloadBean
                mOnSendGiftListener?.onSendGift(
                    SendGiftBean(
                        recipient = userId,
                        giftId = payload.gift.id,
                        count = payload.giftCount,
                        sourceType = sourceType,
                        objectId = objectId
                    )
                )

            }
            //邀请去视频礼物
            R.id.invite_to_call -> {
                if (userId == null) {
                    return
                }

                mOnCallClickListener?.onCall(
                    userId,
                    UserConst.From.LIVE,
                    UserConst.LastFrom.LIVE_DETAIL,
                    LiveConst.SenderFrom.MANUAL
                )
            }
            //提示消息被点击
            R.id.tips_ll -> {
                val payload = item.payload
                if (payload != null && payload is TipsPayloadBean) {
                    if (mLiveInfo?.userId != UserManager.getUserId()) { //主播不能点击
                        payload.gameId?.let { gId ->
                            val roomId = (mLiveInfo?.userId ?: "").toString()
                            val gameData = GameUtils.getLiveCacheGameList()
                                ?.flatMap { it.list }
                                ?.find { it.gameID == gId }
                            gameData?.let {
                                GameUtils.showGameFragment(context, it, roomId = roomId)
                            }
                        }
                    }
                    payload.router?.let { router ->
                        if (router.contains("luckyBag")) {
                            val context = ViewUtils.getAliveTopActivity() ?: return
                            FragmentUtils.getFragmentManager(context)?.showNewDialogFragment(
                                LuckyBagMessageDialogFragment().apply {
                                    arguments = bundleOf("liveId" to mLiveInfo?.userId)
                                },
                                LuckyBagMessageDialogFragment.FRAGMENT_TAG
                            )
                        } else {
                            RouterUtils.routerGoto(router)
                        }
                    }
                }
            }
            //邀请上座信息点击
            R.id.call_up_seat_text, R.id.call_up_seat_im -> {
                mOnSendUpSeatListener?.onUpSeat()
            }
        }
    }

    open fun addMessage(message: SendLiveMessage) {
        val time = System.currentTimeMillis()
        if (mCacheDataSet.isNotEmpty() || time - mLastTime < SEND_MESSAGE_SPACE_TIME) {
            mCacheDataSet.add(0, message)
            postAddMsg()
        } else {
            invokeAddMessage(message)
        }
        mLastTime = time
    }

    private fun postAddMsg() {
        if (mPostMsgJob != null) {
            return
        }

        mPostMsgJob = CoroutineScopeManager.mainScope.launch {
            try {
                delay(SEND_MESSAGE_SPACE_TIME)

                val cacheDataSet = if (mPublicType == CHAT) {
                    mCacheDataSet.filter { it.type == LIVE_PUBLIC_SCREEN }
                } else {
                    mCacheDataSet
                }

                val cacheCount = cacheDataSet.size
                if (cacheCount > 0) {
                    if (cacheCount > CHAT_MAX_NUMBER) {
                        mAdapter.setList(cacheDataSet)
                    } else {
                        val itemCount = mAdapter.data.size
                        val count = min(
                            (cacheCount + itemCount - CHAT_MAX_NUMBER) + CHAT_SINGLE_DELETE_COUNT,
                            mAdapter.itemCount
                        )
                        if (count > 0) {
                            for (i in 0 until count) {
                                mAdapter.data.removeAt(mAdapter.data.size - 1)
                            }
                            mAdapter.notifyItemRangeRemoved(itemCount - 1, itemCount - count - 1)
                        }

                        mAdapter.addData(0, cacheDataSet)
                    }

                    val noHasPublicScreen = cacheDataSet.any { it.type != LIVE_PUBLIC_SCREEN }

                    if (isToBottom(noHasPublicScreen)) {
                        smoothScrollToBottom()
                    }
                }

                mCacheDataSet.clear()
            } finally {
                if (coroutineContext[Job] == mPostMsgJob) {
                    mPostMsgJob = null
                }
            }
        }
    }

    private fun invokeAddMessage(liveMessage: SendLiveMessage) {
        if (mPublicType == CHAT) {
            if (liveMessage.type == LIVE_PUBLIC_SCREEN) {
                mAdapter.addData(0, liveMessage)
            }
        } else {
            mAdapter.addData(0, liveMessage)
        }
        val itemCount = mAdapter.data.size
        if (itemCount >= CHAT_MAX_NUMBER) {
            for (i in 0 until CHAT_SINGLE_DELETE_COUNT) {
                mAdapter.data.removeAt(mAdapter.data.size - 1)
            }
            mAdapter.notifyItemRangeRemoved(itemCount - 1, itemCount - CHAT_SINGLE_DELETE_COUNT - 1)
        }

        if (isToBottom(liveMessage.type != LIVE_PUBLIC_SCREEN)) {
            smoothScrollToBottom()
            handleNotRead(false)
        } else {
            if (isVisible) {
                handleNotRead(true)
            } else {
                smoothScrollToBottom()
                handleNotRead(false)
            }
        }
    }

    fun smoothScrollToBottom() {
        mLayoutManager.scrollToPositionWithOffset(0, 0)
    }

    fun isToBottom(noHasPublicScreen: Boolean): Boolean {
        val position = mLayoutManager.findFirstVisibleItemPosition()
        val isShow = mPublicType == CHAT
                && noHasPublicScreen
                && position <= 1

        return (isToBottom() || isShow)
    }

    protected fun isToBottom(): Boolean {
        return mScrollState == RecyclerView.SCROLL_STATE_IDLE && !mManualScrollFlag
    }

    /**
     * 清除所有关注礼物消息
     */
    fun clearFollower() {
        val list = mutableListOf<SendLiveMessage>()
        mAdapter.data.forEach {
            if (it.type != LIVE_INVITE_FOLLOW) {
                list.add(it)
            }
        }
        mAdapter.setList(list)
    }

    fun hideNotRead() {
        handleNotRead(false)
        mManualScrollFlag = false
    }

    private fun handleNotRead(haveNotRead: Boolean) {
        if (!haveNotRead) {
            mNotReadNum = 0
            mBinding.llNotLook.visibility = View.GONE
        } else {
            mNotReadNum += 1
            mBinding.notLookText.text =
                "$mNotReadNum ${StringUtils.getString(string.not_look_message)}"
            mBinding.llNotLook.visibility = View.VISIBLE
        }
    }

    //重置ui
    @CallSuper
    open fun reset() {
        mAdapter.data.clear()
        mAdapter.notifyDataSetChanged()

        cancelPostJob()
    }

    fun setOnItemChildClickListener(listener: OnItemChildClickListener?) {
        mAdapter.setOnItemChildClickListener(listener)
    }

    fun setOnSendGiftListener(l: OnSendGiftListener) {
        this.mOnSendGiftListener = l
    }

    fun setOnSendUpSeatListener(l: OnSendUpSeatListener) {
        this.mOnSendUpSeatListener = l
    }

    fun setOnSendFollowerListener(l: OnSendFollowerListener) {
        this.mOnSendFollowerListener = l
    }

    fun setOnUserProfileClickListener(l: OnUserProfileClickListener) {
        this.mOnUserProfileClickListener = l
    }

    fun setOnReportListener(l: OnReportListener) {
        this.mOnReportListener = l
    }

    fun setOnCallClickListener(l: OnCallClickListener) {
        this.mOnCallClickListener = l
    }

    /**
     * 送完邀请关注礼物
     */
    fun changeAddFollowerMessage(position: Int) {
        mAdapter.removeAt(position)
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        parent.requestDisallowInterceptTouchEvent(true)
        return super.dispatchTouchEvent(ev)
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()

        cancelPostJob()
    }

    private fun cancelPostJob() {
        mPostMsgJob?.cancel()
        mPostMsgJob = null
    }

    companion object {

        /**
         * 全部
         */
        const val ALL = 1

        /**
         * 只展示主播消息和观众消息
         */
        const val CHAT = 2

        /**
         * 最大留存条数
         */
        const val CHAT_MAX_NUMBER = 500

        /**
         * 单次删除数量
         */
        const val CHAT_SINGLE_DELETE_COUNT = 10

        /**
         * 毫秒
         */
        const val SEND_MESSAGE_SPACE_TIME = 100L

    }
}

class BaseMessageView(context: Context, attributeSet: AttributeSet) :
    AbstractLiveMessageView(context, attributeSet) {

    //所有的消息
    private val mAllMessage = mutableListOf<SendLiveMessage>()
    private val mChatMessage = mutableListOf<SendLiveMessage>()

    //公屏消息切换  切换成全部或者文字消息
    fun changeMessage(type: Int) {
        mPublicType = type
        if (type == ALL) {
            mAdapter.setList(mAllMessage)
        } else {
            mAdapter.setList(mChatMessage)
        }
        hideNotRead()
        smoothScrollToBottom()
    }

    override fun addMessage(message: SendLiveMessage) {
        super.addMessage(message)

        mAllMessage.add(0, message)
        if (mAllMessage.size >= CHAT_MAX_NUMBER) {
            (0 until CHAT_SINGLE_DELETE_COUNT).forEach {
                mAllMessage.removeAt(mAllMessage.size - 1)
            }
        }
        if (message.type == LIVE_PUBLIC_SCREEN) {
            mChatMessage.add(0, message)
            if (mChatMessage.size >= CHAT_MAX_NUMBER) {
                (0 until CHAT_SINGLE_DELETE_COUNT).forEach {
                    mChatMessage.removeAt(mChatMessage.size - 1)
                }
            }
        }
    }

    fun getAllMessageList(): MutableList<SendLiveMessage> {
        return mAllMessage
    }
}

class GameCallMessageView(context: Context, attributeSet: AttributeSet) :
    LinearLayout(context, attributeSet) {

    val mBinding = WidgetGameCallMessageBinding.inflate(LayoutInflater.from(context), this)
    private val mOriginalHeight: Int = 100.dp //原始高度
    private val mOriginalHeight2: Int = 400.dp //原始高度
    private var mHeight: Int = mOriginalHeight
    private var mType = TYPE_NONE //  -1 未设置  1 普通  2 半屏  3 键盘弹出

    private var mOnCallback: (() -> Unit)? = null

    init {
        mBinding.apply {
            baseMessage.setOnItemChildClickListener { _, view, position ->
                if (baseMessage.mLivePage == null) {
                    return@setOnItemChildClickListener
                }
                val userId = baseMessage.mLiveInfo?.userId
                val sourceType = AppConst.GiftComming.LIVE
                val objectId = baseMessage.mLiveInfo?.liveId
                baseMessage.itemClick(view.id, position, userId, sourceType, objectId)
            }

            allLl.setOnSingleClickListener {
                textAll.setTextColor(ContextCompat.getColor(context, R.color.white))
                textChat.setTextColor(ContextCompat.getColor(context, R.color.ffffff_50))
                textAll.setTypeface(null, Typeface.BOLD)
                textChat.setTypeface(null, Typeface.NORMAL)
                allLine.visibility = View.VISIBLE
                chatLine.visibility = View.INVISIBLE
                baseMessage.changeMessage(AbstractLiveMessageView.ALL)
            }
            chatLl.setOnSingleClickListener {
                textAll.setTextColor(ContextCompat.getColor(context, R.color.ffffff_50))
                textChat.setTextColor(ContextCompat.getColor(context, R.color.white))
                textAll.setTypeface(null, Typeface.NORMAL)
                textChat.setTypeface(null, Typeface.BOLD)
                allLine.visibility = View.INVISIBLE
                chatLine.visibility = View.VISIBLE
                baseMessage.changeMessage(CHAT)
            }
            topBtn.setOnSingleClickListener {
                mType = if (mType == TYPE_NORMAL) {
                    TYPE_HALF
                } else {
                    TYPE_NORMAL
                }
                setView()
            }
        }
        //注册软键盘监听
        KeyboardUtils.registerSoftInputChangedListener(ViewUtils.requireWindow(context)) {
            if (mType == TYPE_HALF) {
                if (it > 0) {

                    mBinding.topBtn.setImageResource(R.drawable.party_game_message_down)
                    setBackgroundColor(ContextCompat.getColor(context, R.color.color_F21d1928))
                    val lp = layoutParams as ConstraintLayout.LayoutParams
                    lp.bottomMargin = it
                    layoutParams = lp

                    val lp2 = mBinding.topControl.layoutParams as MarginLayoutParams
                    lp2.topMargin = 10.dp
                    mBinding.topControl.layoutParams = lp2

                    val lp3 = mBinding.baseMessage.layoutParams as MarginLayoutParams
                    lp3.bottomMargin = 10.dp
                    mBinding.baseMessage.layoutParams = lp3
                } else {
                    setView()
                }
            }
        }

    }

    fun setMessageHeight(h: Int) {
        mHeight = h
        setView()
    }

    /**
     * 回到普通界面
     */
    fun closeMessage() {
        if (mType != TYPE_NORMAL) {
            mType = TYPE_NORMAL
            setView()
        }
    }

    private fun setView() {
        when (mType) {
            TYPE_NORMAL, TYPE_NONE -> {
                mBinding.topBtn.setImageResource(R.drawable.party_game_message_top)
                setBackgroundResource(0)
                setBackgroundColor(0)
                val lp = layoutParams as ConstraintLayout.LayoutParams
                lp.height = mHeight
                lp.bottomMargin = 0
                layoutParams = lp

                val lp2 = mBinding.topControl.layoutParams as MarginLayoutParams
                lp2.topMargin = 0.dp
                mBinding.topControl.layoutParams = lp2

                val lp3 = mBinding.baseMessage.layoutParams as MarginLayoutParams
                lp3.bottomMargin = 0.dp
                mBinding.baseMessage.layoutParams = lp3

                if (mBinding.baseMessage.isToBottom(false)) {
                    mBinding.baseMessage.smoothScrollToBottom()
                }
            }

            TYPE_HALF -> {
                mBinding.topBtn.setImageResource(R.drawable.party_game_message_down)
                setBackgroundResource(R.drawable.r14_back_1d1928_tltr)
                val lp = layoutParams as ConstraintLayout.LayoutParams
                lp.height = mOriginalHeight2
                lp.bottomMargin = 0
                layoutParams = lp

                val lp2 = mBinding.topControl.layoutParams as MarginLayoutParams
                lp2.topMargin = 10.dp
                mBinding.topControl.layoutParams = lp2

                val lp3 = mBinding.baseMessage.layoutParams as MarginLayoutParams
                lp3.bottomMargin = 10.dp
                mBinding.baseMessage.layoutParams = lp3
            }
        }
    }

    fun setOnClick(onCallback: () -> Unit) {
        mOnCallback = onCallback
    }

    private val mOnGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
        if (mType == TYPE_NONE) {
            val lp = layoutParams as ConstraintLayout.LayoutParams
            lp.height = mHeight
            layoutParams = lp
            mType = TYPE_NORMAL
        }
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        rootView.viewTreeObserver.addOnGlobalLayoutListener(mOnGlobalLayoutListener)
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        rootView.viewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener)
        KeyboardUtils.unregisterSoftInputChangedListener(ViewUtils.requireWindow(context))
    }

    fun initData(@LivePage page: Int, liveInfo: LiveRoomInfo) {
        ViewTreeLifecycleOwner.set(mBinding.baseMessage, findViewTreeLifecycleOwner())
        mBinding.baseMessage.initData(page, liveInfo)
    }

    fun addMessage(liveMessage: SendLiveMessage) {
        mBinding.baseMessage.addMessage(liveMessage)
    }

    //重置ui
    fun reset() {
        mBinding.baseMessage.reset()
    }

    companion object {

        const val TYPE_NONE = -1    //未设置
        const val TYPE_NORMAL = 1   //普通
        const val TYPE_HALF = 2     //半屏
        const val TYPE_KEYBOARD = 3 //键盘弹出

    }
}

class GamePartyMessageView(context: Context, attributeSet: AttributeSet) :
    LinearLayout(context, attributeSet) {

    val mBinding = WidgetPartyGameMessageBinding.inflate(LayoutInflater.from(context), this)

    private var mBottomMargin: Int = 0  //这个控件的Top点
    private var mRightMargin: Int = 0  //这个控件的Left点
    private var mMarginLeft: Int = 8.dp
    private var mMarginTop: Int = 0
    private var mOriginalMarginTop: Int = ScreenUtils.getScreenWidth() + 36.dp
    private var mOriginalHeight: Int = 0 //原始高度
    private var mType = TYPE_NONE //  -1 未设置  1 普通  2 半屏  3 键盘弹出

    private var mOnCallback: (() -> Unit)? = null

    init {
        mBinding.apply {
            baseMessage.setOnItemChildClickListener { _, view, position ->
                if (baseMessage.mLivePage == null) {
                    return@setOnItemChildClickListener
                }
                val userId = baseMessage.mLiveInfo?.userId
                val sourceType = AppConst.GiftComming.LIVE
                val objectId = baseMessage.mLiveInfo?.liveId
                baseMessage.itemClick(view.id, position, userId, sourceType, objectId)
            }

            allLl.setOnSingleClickListener {
                textAll.setTextColor(ContextCompat.getColor(context, R.color.white))
                textChat.setTextColor(ContextCompat.getColor(context, R.color.ffffff_50))
                textAll.setTypeface(null, Typeface.BOLD)
                textChat.setTypeface(null, Typeface.NORMAL)
                allLine.visibility = View.VISIBLE
                chatLine.visibility = View.INVISIBLE
                baseMessage.changeMessage(AbstractLiveMessageView.ALL)
            }
            chatLl.setOnSingleClickListener {
                textAll.setTextColor(ContextCompat.getColor(context, R.color.ffffff_50))
                textChat.setTextColor(ContextCompat.getColor(context, R.color.white))
                textAll.setTypeface(null, Typeface.NORMAL)
                textChat.setTypeface(null, Typeface.BOLD)
                allLine.visibility = View.INVISIBLE
                chatLine.visibility = View.VISIBLE
                baseMessage.changeMessage(CHAT)
            }
            topBtn.setOnSingleClickListener {
                mType = if (mType == TYPE_NORMAL) {
                    TYPE_HALF
                } else {
                    TYPE_NORMAL
                }
                setView()
            }
            senderMessage.setOnSingleClickListener {
                mOnCallback?.invoke()
            }
        }
        //注册软键盘监听
        KeyboardUtils.registerSoftInputChangedListener(ViewUtils.requireWindow(context)) {
            if (mType == TYPE_HALF) {
                if (it > 0) {
                    mBinding.senderMessage.visibility = View.GONE
                    mBinding.topBtn.setImageResource(R.drawable.party_game_message_down)
                    setBackgroundColor(ContextCompat.getColor(context, R.color.color_F21d1928))
                    val lp = layoutParams as ConstraintLayout.LayoutParams
                    lp.bottomMargin = it
                    lp.topMargin = 0
                    layoutParams = lp

                    val lp2 = mBinding.topControl.layoutParams as MarginLayoutParams
                    lp2.topMargin = 10.dp
                    mBinding.topControl.layoutParams = lp2

                    val lp3 = mBinding.baseMessage.layoutParams as MarginLayoutParams
                    lp3.bottomMargin = 10.dp
                    mBinding.baseMessage.layoutParams = lp3
                } else {
                    setView()
                }
            }
        }

    }

    fun setMessageHeight(h: Int) {
        mMarginTop = if (h == -1) {
            mOriginalMarginTop
        } else {
            mOriginalHeight - h - mBottomMargin
        }
        setView()
    }

    /**
     * 回到普通界面
     */
    fun closeMessage() {
        if (mType != TYPE_NORMAL) {
            mType = TYPE_NORMAL
            setView()
        }
    }

    private fun setView() {
        when (mType) {
            TYPE_NORMAL, TYPE_NONE -> {
                mBinding.senderMessage.visibility = View.GONE
                mBinding.topBtn.setImageResource(R.drawable.party_game_message_top)
                setBackgroundResource(0)
                setBackgroundColor(0)
                val lp = layoutParams as ConstraintLayout.LayoutParams
                lp.leftMargin = mMarginLeft
                lp.topMargin = mMarginTop
                lp.rightMargin = mRightMargin
                lp.bottomMargin = mBottomMargin
                layoutParams = lp

                val lp2 = mBinding.topControl.layoutParams as MarginLayoutParams
                lp2.topMargin = 0.dp
                mBinding.topControl.layoutParams = lp2

                val lp3 = mBinding.baseMessage.layoutParams as MarginLayoutParams
                lp3.bottomMargin = 0.dp
                mBinding.baseMessage.layoutParams = lp3

                if (mBinding.baseMessage.isToBottom(false)) {
                    mBinding.baseMessage.smoothScrollToBottom()
                }
            }

            TYPE_HALF -> {
                mBinding.senderMessage.visibility = View.VISIBLE
                mBinding.topBtn.setImageResource(R.drawable.party_game_message_down)
                setBackgroundResource(R.drawable.r14_back_1d1928_tltr)
                val lp = layoutParams as ConstraintLayout.LayoutParams
                lp.leftMargin = 0
                lp.topMargin = 200.dp
                lp.rightMargin = 0
                lp.bottomMargin = 0
                layoutParams = lp

                val lp2 = mBinding.topControl.layoutParams as MarginLayoutParams
                lp2.topMargin = 10.dp
                mBinding.topControl.layoutParams = lp2

                val lp3 = mBinding.baseMessage.layoutParams as MarginLayoutParams
                lp3.bottomMargin = 10.dp
                mBinding.baseMessage.layoutParams = lp3
            }
        }
    }

    fun setOnClick(onCallback: () -> Unit) {
        mOnCallback = onCallback
    }

    private val mOnGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
        if (mBottomMargin == 0) {
            val view = rootView.findViewById<PartyBottomView>(R.id.bottom)
            val location = IntArray(2)
            view.getLocationOnScreen(location)
            val y = location[1]
            mBottomMargin = if (view == null) {
                44.dp
            } else {
                if (y < 0) {
                    abs(y)
                } else {
                    rootView.height - y
                }
            }
        }
        if (mRightMargin == 0) {
            if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
                mRightMargin = 8.dp
                mMarginLeft = 68.dp
            } else {
                mRightMargin = 68.dp
            }

        }
        if (mType == TYPE_NONE) {
            mOriginalHeight = height
            val lp = layoutParams as ConstraintLayout.LayoutParams
            mMarginTop = mOriginalMarginTop
            lp.leftMargin = mMarginLeft
            lp.topMargin = mMarginTop
            lp.rightMargin = mRightMargin
            lp.bottomMargin = mBottomMargin
            layoutParams = lp
            mType = TYPE_NORMAL
        }
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        rootView.viewTreeObserver.addOnGlobalLayoutListener(mOnGlobalLayoutListener)
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        rootView.viewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener)
        KeyboardUtils.unregisterSoftInputChangedListener(ViewUtils.requireWindow(context))
    }

    fun initData(@LivePage page: Int, liveInfo: LiveRoomInfo) {
        ViewTreeLifecycleOwner.set(mBinding.baseMessage, findViewTreeLifecycleOwner())
        mBinding.baseMessage.initData(page, liveInfo)
    }

    fun addMessage(liveMessage: SendLiveMessage) {
        mBinding.baseMessage.addMessage(liveMessage)
    }

    //重置ui
    fun reset() {
        mBinding.baseMessage.reset()
    }

    companion object {

        const val TYPE_NONE = -1    //未设置
        const val TYPE_NORMAL = 1   //普通
        const val TYPE_HALF = 2     //半屏
        const val TYPE_KEYBOARD = 3 //键盘弹出

    }
}

class PartyMessageView(context: Context, attributeSet: AttributeSet) :
    LinearLayout(context, attributeSet) {

    val mBinding = WidgetPartyMessageBinding.inflate(LayoutInflater.from(context), this)

    init {
        mBinding.apply {
            baseMessage.setOnItemChildClickListener { _, view, position ->
                if (baseMessage.mLivePage == null) {
                    return@setOnItemChildClickListener
                }
                val userId = baseMessage.mLiveInfo?.userId
                val sourceType = AppConst.GiftComming.LIVE
                val objectId = baseMessage.mLiveInfo?.liveId
                baseMessage.itemClick(view.id, position, userId, sourceType, objectId)
            }

            allLl.setOnSingleClickListener {
                textAll.setTextColor(ContextCompat.getColor(context, R.color.white))
                textChat.setTextColor(ContextCompat.getColor(context, R.color.ffffff_50))
                textAll.setTypeface(null, Typeface.BOLD)
                textChat.setTypeface(null, Typeface.NORMAL)
                allLine.visibility = View.VISIBLE
                chatLine.visibility = View.GONE
                baseMessage.changeMessage(AbstractLiveMessageView.ALL)
            }
            chatLl.setOnSingleClickListener {
                textAll.setTextColor(ContextCompat.getColor(context, R.color.ffffff_50))
                textChat.setTextColor(ContextCompat.getColor(context, R.color.white))
                textAll.setTypeface(null, Typeface.NORMAL)
                textChat.setTypeface(null, Typeface.BOLD)
                allLine.visibility = View.GONE
                chatLine.visibility = View.VISIBLE
                baseMessage.changeMessage(CHAT)
            }
        }
    }

    fun initData(@LivePage page: Int, liveInfo: LiveRoomInfo) {
        ViewTreeLifecycleOwner.set(mBinding.baseMessage, findViewTreeLifecycleOwner())
        mBinding.baseMessage.initData(page, liveInfo)
    }

    fun addMessage(liveMessage: SendLiveMessage) {
        mBinding.baseMessage.addMessage(liveMessage)
    }

    /**
     * 返回新的对象
     */
    fun getAllMessageList(): MutableList<SendLiveMessage> {
        return mBinding.baseMessage.getAllMessageList()
            .map { it.copy() }
            .toMutableList()
    }

    //重置ui
    fun reset() {
        mBinding.baseMessage.reset()
    }
}

class LiveMessageView(context: Context, attributeSet: AttributeSet) :
    LinearLayout(context, attributeSet) {

    val mBinding = WidgetLiveMessageBinding.inflate(LayoutInflater.from(context), this)

    init {
        mBinding.apply {
            baseMessage.setOnItemChildClickListener { _, view, position ->
                if (baseMessage.mLivePage == null) {
                    return@setOnItemChildClickListener
                }
                val userId = baseMessage.mLiveInfo?.userId
                val sourceType = AppConst.GiftComming.LIVE
                val objectId = baseMessage.mLiveInfo?.liveId
                baseMessage.itemClick(view.id, position, userId, sourceType, objectId)
            }
            //切换全部和聊天
            allChat.setOnChatClientListener {//聊天
                baseMessage.changeMessage(CHAT)
            }
            allChat.setOnAllClientListener {//全部
                baseMessage.changeMessage(AbstractLiveMessageView.ALL)
            }
        }

    }

    fun initData(@LivePage page: Int, liveInfo: LiveRoomInfo) {
        ViewTreeLifecycleOwner.set(mBinding.baseMessage, findViewTreeLifecycleOwner())
        mBinding.baseMessage.initData(page, liveInfo)
    }

    fun getMessageView(): BaseMessageView {
        return mBinding.baseMessage
    }

    fun addMessage(liveMessage: SendLiveMessage) {
        mBinding.baseMessage.addMessage(liveMessage)
    }

    //重置ui
    fun reset() {
        mBinding.baseMessage.reset()
    }

    fun setOnCallClickListener(l: OnCallClickListener) {
        mBinding.baseMessage.setOnCallClickListener(l)
    }
}

class CallMessageView(context: Context, attributeSet: AttributeSet) :
    LinearLayout(context, attributeSet) {

    val mBinding = WidgetCallMessageBinding.inflate(LayoutInflater.from(context), this)

    private var mCallInfo: CallVo? = null

    init {
        mBinding.apply {
            baseMessage.setOnItemChildClickListener { _, view, position ->
                if (baseMessage.mLivePage == null || mCallInfo == null) {
                    return@setOnItemChildClickListener
                }

                val otherUserId = if (mCallInfo?.senderId != UserManager.getUserId()) {
                    mCallInfo?.senderId
                } else {
                    mCallInfo?.answerId
                }
                val sourceType = AppConst.GiftComming.CALL
                val objectId = mCallInfo?.id

                baseMessage.itemClick(view.id, position, otherUserId, sourceType, objectId)
            }
        }
    }

    fun getMessageView(): AbstractLiveMessageView {
        return mBinding.baseMessage
    }

    fun initData(@LivePage page: Int, callInfo: CallVo) {
        ViewTreeLifecycleOwner.set(mBinding.baseMessage, findViewTreeLifecycleOwner())
        mBinding.baseMessage.initPage(page)
        mCallInfo = callInfo
    }

    //重置ui
    fun reset() {
        mBinding.baseMessage.reset()
    }
}